"""
1. Generate ie6 module with win32/com/tools/readtlb.py from the ctypes
 package

 (I forget the details, but you can probably skip this and just use
  ie6_gen.py that comes with ctypes in the samples directory -- change
  the 'import ie6' below as appropriate.)

2. Generate a GUID and cut-n-paste it as PythonBHO._reg_clsid_.  To
 generate a GUID using pywin32 (aka "Python for Windows Extensions"):

import pythoncom
pythoncom.CreateGUID()

3. python bho_skel.py /regserver

4. Use DebugView or similar to see the output from print statements.

5. Run IE, watch output (IIRC dispinterface_EventReceiver prints out
 messages for unimplemented events).

6. Remember to write something useful ;-)

"""

import sys
import _winreg

from ctypes import *
from ctypes.com import IUnknown, PIUnknown, REFIID, GUID, STDMETHOD, HRESULT, \
     COMObject
from ctypes.com.automation import IDispatch, BSTR, VARIANT, \
                                  dispinterface, DISPMETHOD
from ctypes.com.register import Registrar
from ctypes.com.connectionpoints import dispinterface_EventReceiver, \
     GetConnectionPoint

import ie6  # module generated by ctypes/com/tools/readtlb.py

# _Logger is pinched from ctypes 0.6.2
# --------------------------------------------------------------------
from ctypes import windll
kernel32 = windll.kernel32

# Hm. We cannot redirect sys.stderr/sys.stdout in the inproc case,
# If the process is Python, the user would be pissed off if we did.
class _Logger(object):
    # Redirect standard output and standard error to
    # win32 Debug Messages. Output can be viewed for example
    # in DebugView from www.sysinternals.com
    _installed = 0
    _text = ""
    def write(self, text):
        self._text += str(text)
        if "\n" in self._text:
            kernel32.OutputDebugStringA(self._text)
            self._text = ""

    def install(cls):
        if cls._installed:
            return
        import sys
        sys.stdout = sys.stderr = cls()
        cls._installed = 1
    install = classmethod(install)

    def isatty(self):
        return 0
# --------------------------------------------------------------------

_Logger.install()  # redirect stdout to win32's OutputDebugStringA()

HKLM = _winreg.HKEY_LOCAL_MACHINE
BHO_KEY = ("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\"
           "Browser Helper Objects\\")
class MyRegistrar(Registrar):
    def build_table(self):
        table = Registrar.build_table(self)
        table.extend([(HKLM, BHO_KEY+self._reg_clsid_, "", None)])
        return table

class IObjectWithSite(IUnknown):
    _iid_ = GUID("{FC4801A3-2BA9-11CF-A229-00AA003D7352}")

IObjectWithSite._methods_ = IUnknown._methods_ + [
    (STDMETHOD(HRESULT, "SetSite", PIUnknown)),
    (STDMETHOD(HRESULT, "GetSite", POINTER(c_void_p), REFIID))]

class PythonBHO(COMObject):
    _reg_clsid_ = "{693D1AC0-2D77-11D8-9B9E-FB41F7E93A45}"
    _reg_progid_ = "PythonBHO"
    _com_interfaces_ = [IObjectWithSite]

    def _get_registrar(cls):
        return MyRegistrar(cls)
    _get_registrar = classmethod(_get_registrar)

    def IObjectWithSite_SetSite(self, this, pUnkSite):
        self.browser = POINTER(ie6.IWebBrowser2)()
        hr = pUnkSite.QueryInterface(
            byref(ie6.IWebBrowser2._iid_), byref(self.browser))
        sink = DWebBrowserEvents2Impl()
        sink.handle = sink.connect(self.browser)

class DWebBrowserEvents2Impl(dispinterface_EventReceiver):
    _com_interfaces_ = [ie6.DWebBrowserEvents2]

    def OnQuit(self, this, *args):
        self.disconnect(self.handle)

    def BeforeNavigate2(self, this, pDisp, url, Flags, TargetFrameName,
                        PostData, Headers, Cancel):
        print "url", url

if __name__ == '__main__':
    from ctypes.com.server import UseCommandLine
    UseCommandLine(PythonBHO)
